package cn.iune.config;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
//import org.apache.shiro.session.Session;
//import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
//import org.apache.shiro.subject.support.DefaultSubjectContext;

import com.alibaba.fastjson.JSONObject;

import cn.iune.backcenter.authen.IAuthenticationService;
import cn.iune.backcenter.authen.SaOpperson;
import cn.iune.backcenter.author.ISaOpauthorizeService;
import cn.iune.backcenter.author.ISaOporgService;
import cn.iune.backcenter.author.ISaOppermissionService;
import cn.iune.backcenter.author.SaOporg;
import cn.iune.backcenter.author.SaOppermission;
import cn.iune.backcenter.author.sysinfo.ISysInfoService;
import cn.iune.backcenter.author.sysinfo.SysInfo;
import cn.iune.system.spring.SpringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set; 

//@Service("myRealm1")
public class MyRealm extends AuthorizingRealm {  

//	@Autowired
//	@Lazy
	private IAuthenticationService authenticationService;
//	@Autowired
//	@Lazy
//	private SessionDAO sessionDAO;
	
//	@Autowired  
    private ISaOporgService saOporgService;
//	@Autowired  
    private ISaOpauthorizeService saOpauthorizeService;
//	@Autowired  
    private ISaOppermissionService saOppermissionService;
	
//	@Autowired
	private ISysInfoService sysInfoService;

	/** 
     * 登录认证; 
     */  
	
	
    @Override  
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {  
    	System.out.println("登录认证--doGetAuthenticationInfo");
    	//登录执行顺序2
       //UsernamePasswordToken对象用来存放提交的登录信息  
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;  

        String username = token.getUsername();
        String password = String.valueOf(token.getPassword());
    	System.out.println("登录认证--password:"+password);
    	authenticationService = SpringUtils.getBean(IAuthenticationService.class);
        SaOpperson person = authenticationService.getByUsername(username);
        //查出是否有此用户  
        if (person==null){
        	//用户名不存在
    		throw new UnknownAccountException("user does not exist!");  
        }else if(!password.equals(person.getsPassword())){
        	//密码不匹配
        	throw new IncorrectCredentialsException("passwork mismatch!");  
        }else{  
        	//经过与数据库中的用户数据核对，验证用户存在并一切正常
        	//登录验证通过！！！！！！！！！！！！！！！！！！！！！！！！！！！！！
        	
    		//踢掉登录名相同的用户，重新登陆（不能放在前一环节的控制器中提示已登陆，因为前一环节不包含登录名）
        	String sLoginName = person.getsLoginName();
        	
//        	sessionDAO = SpringUtils.getBean(SessionDAO.class);
//            Collection<Session> sessions = sessionDAO.getActiveSessions();
//            for(Session session:sessions){
//    	        if(sLoginName.equals(String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)))) {
//    	        	session.setTimeout(0);//设置session立即失效，即将其踢出系统，为负数时表示永不超时(-1000)，所有要是除以1000以后还是负数，必须设置小于-1000
//    	        	System.out.println("踢掉在线用户："+sLoginName+"（"+ session.getId() +"）");
//    		        break;
//    	        }
//            }
            
    		
        	//经过与数据库中的用户数据核对，验证用户存在并一切正常
        	//登录验证通过！！！！！！！！！！！！！！！！！！！！！！！！！！！！！
        	//登录成功。。。。
    		//踢掉登录名相同的用户，重新登陆（不能放在前一环节的控制器中提示已登陆，因为前一环节不包含登录名）
        	String personID = person.getsID();
            
            //认证成功后记录
//	        System.out.println("ShiroSession SESSION ID = " + sessionId); 
//	        System.out.println("用户名：" + currentUser.getPrincipal()); 
//	        System.out.println("HOST：" + currentUser.getSession().getHost()); 
//	        System.out.println("TIMEOUT ：" + currentUser.getSession().getTimeout()); 
//	        System.out.println("START：" + currentUser.getSession().getStartTimestamp()); 
//	        System.out.println("LAST：" + currentUser.getSession().getLastAccessTime());
    		
    		//登录成功
        	JSONObject json = new JSONObject();
        	json.put("sLoginName", person.getsLoginName());
        	json.put("userId", person.getsID());
        	json.put("cUsercode", person.getsCode());
        	json.put("cUsername", person.getsName());
        	
    		/*
    		 * Collection<Session> sessions = sessionDAO.getActiveSessions(); for(Session
    		 * shiroSession:sessions){
    		 * if(sLoginName.equals(String.valueOf(shiroSession.getAttribute(
    		 * DefaultSubjectContext.PRINCIPALS_SESSION_KEY)))) {
    		 * shiroSession.setTimeout(0);//设置session立即失效，即将其踢出系统，为负数时表示永不超时(-1000)，
    		 * 所有要是除以1000以后还是负数，必须设置小于-1000 System.out.println("踢掉在线用户："+sLoginName+"（"+
    		 * shiroSession.getId() +"）"); break; } }
    		 */
        	
        	//用户没有登录，不影响将信息登记到该session
        	
        	//记录当前人员
        	SecurityService.setCurrentPerson(json);
        	//设置组织和成员信息（写入当前session）
//          List<SaOporg> saOporgList = saOporgService.getOgnsBysCreatorFID(person.getsID());
//          SecurityService.setCurrentOgnList(saOporgList);
        	
//          SaOporg ogn = SecurityService.getCurrentOgn();
        	saOporgService = SpringUtils.getBean(ISaOporgService.class);
        	List<SaOporg> saOporgpsmList = saOporgService.getByPersonID(personID);
//          List<SaOporg> saOporgpsmList = saOporgService.getPersonMembers(person.getsID(),ogn.getsID());
        	SecurityService.setCurrentPsmList(saOporgpsmList);
        	
        	//如果只有一个人员成员，那么就设定为当前
        	if(saOporgpsmList==null) {
        		SecurityService.setCurrentPsm(null);
        	}else {
            	if(saOporgpsmList.size()==1) {
            		SecurityService.setCurrentPsm(saOporgpsmList.get(0));
        			
        			////////////////////加载公司及公司所绑定的应用/////////////////////////
            		//根据当前人员成员获取当前公司（最近的上级公司）
            		SaOporg topOgn = saOporgService.getCompany(SecurityService.getCurrentPsm());
            		SecurityService.setCurrentOgn(topOgn);
            		//判断是否有默认登录的应用，如果没有就使用第一个登录
//            		if(list.size()>0) {
//            			SecurityService.setCurrentAppId(list.get(0).getAppId());
//            			SecurityService.setCurrentAppName(list.get(0).getAppName());
//            		}
            		////////////////////////////////////////////////////////////////////////////

            	}else {
            		SecurityService.setCurrentPsm(null);
            	}
        	}

        	
            //验证通过，将此用户存放到登录认证info中
        	return new SimpleAuthenticationInfo(sLoginName, person.getsPassword(), getName());
        }  
        
    }  
    

	
//	@Override
//	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//		// TODO Auto-generated method stub
//		return null;
//	}  

	
	@Override
	public AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
		// TODO Auto-generated method stub
		AuthorizationInfo info = super.getAuthorizationInfo(principals);
		return info;
	}

	/** 
     * 登录认证后授权认证; 
     */  
   
    @Override  
    public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  
		System.out.println("授权认证--doGetAuthorizationInfo");

        if (principals == null) {
//			System.out.println("授权--Principal对象不能为空");
			//SecurityUtils.getSubject().logout();
            throw new AuthorizationException("Principal对象不能为空"); 
//            return info;
        }
        
        Set<String> realmRoles = new HashSet<String>();
        //Collection<String> realmPermissions = new ArrayList<String>();
        Set<String> realmPermissions = new HashSet<String>();
        
        /*
		String sLoginName = (String) principals.fromRealm(this.getName()).iterator().next();  
		SaOpperson person = saOppersonService.getByLoginName(sLoginName);

		///////////////////为创始人账号增加前台管理特权/////////////////////////////
        if(person.getsID().equals(person.getsCreatorFID())){
        	//是创始人账号
            realmRoles.add("userAdmin");
        }
        ///////////////////////////////////////////////////////////////////////////
    	
		///////////////////为system账号增加后台管理特权/////////////////////////////
        //下面这两个用户为系统保留
        if("system".equals(person.getsLoginName()) || "root".equals(person.getsLoginName())){
            realmRoles.add("backAdmin");
        }
        ///////////////////////////////////////////////////////////////////////////
        */
        
        //与人员成员相关的权限
		SaOporg psm = SecurityService.getCurrentPsm();
		if(psm==null){
			System.out.println("saOporg-->当前组织为空！无需加载组织相关的授权！");
		}else{
			System.out.println("saOporg当前组织-->"+psm.getsFName());
	        
	        //取得授权的同时，取得systemFullID，用于左侧树形菜单显示
	        List<String> systemFullIDs = new ArrayList<>();
	        
	        //获取数据访问权限
	        List<String> dataAccessIDs = new ArrayList<String>();
	        //获取数据访问权限是否启用，如果没有启用，则数据访问权限不起作用
	        Map<String,String> dataAccessUrls = new HashMap<String,String>();
			
	        //获取SysInfo中的标配叶子（pag）列表
//	        JSONArray arrs = appPreloading.getSysInfoPags();
//	        List<SysInfo> sysInfoPags = AppSystemService.getListByArray(SysInfo.class, arrs.toJSONString());
	        
//			String appId = AppConfigParams.APPID;
	        String appId = SecurityService.getCurrentAppId();
	        
//			System.out.println("Oauth2Realm-->>appId-->>"+appId);
	        sysInfoService = SpringUtils.getBean(ISysInfoService.class);    
		    List<SysInfo> sysInfoPags = sysInfoService.getPagList(appId);
//			List<SysInfo> sysInfoPags = sysInfoCache.getPagList();
	        System.out.println("sysInfoPags.size()-->>"+sysInfoPags.size());
	        
	        //根据人员获取全部相关的组织关系
//			List<SaOporg> saOporgList = saOporgUtil.getPersonOrgs(person);
			//根据人员成员获取上级组织关系（，包含当前人员成员，到当前公司为止）
        	saOporgService = SpringUtils.getBean(ISaOporgService.class);
			List<SaOporg> saOporgList = saOporgService.getSuperiors(psm);
	        //打印当前人员的全部组织关系
//	        for(SaOporg obj : saOporgList){
//	        	System.out.println(obj.getsFName()+"----"+obj.getsLevel());
//	        }
	        
	        //2根据人员查找到我们定义的角色（相当于realm的角色组）
//	        List<String> saOproleIDList = new ArrayList<String>();
	        //3根据我们定义的角色ID列表获取功能权限列表，就是realm定义的角色和权限
	        
	        //从授权列表中获取对应的roleID
			saOpauthorizeService = SpringUtils.getBean(ISaOpauthorizeService.class);

	        Set<String> roleIDs = saOpauthorizeService.getRoleIDs(saOporgList);//new HashSet<String>();
	        System.out.println("roleIDs.size()-->>"+roleIDs.size());
	        
//			String appId = AppConfigParams.APPID;
//			String appId = appConfigParams.getAppId();
	        
	        for(String saOproleID : roleIDs){
	        	//循环我们自定义的角色id
	        	saOppermissionService = SpringUtils.getBean(ISaOppermissionService.class);
	        	List<SaOppermission> saOppermissionList = saOppermissionService.getByPermissionRoleID(saOproleID);
		        System.out.println("saOppermissionList.size()-->>"+saOppermissionList.size());
	            for(SaOppermission saOppermission : saOppermissionList){
            		String systemFullID = saOppermission.getSystemFullID();
	            	String sDisplay = "N";//菜单是否显示
	            	//首先判断是否为本应用的权限
	            	boolean isMyApp = false;
		            for(SysInfo sysInfoPag: sysInfoPags) {
		            	if(systemFullID.equals(sysInfoPag.getSystemFullID())) {
		            		//获取菜单显示与否的值
		            		sDisplay = sysInfoPag.getsDisplay();
		            		//判断是否为本应用
			            	//System.out.println("非本应用所属权限，无需赋权-->>"+AppConfigParams.APPID);
		            		if(sysInfoPag.getAppId().equals(appId)) {
		            			isMyApp = true;
		            		}
		            	}
		            }
		            //非本应用所属权限，无需赋权
		            
		            if(isMyApp==false) {
//		            	System.out.println("非本应用所属权限，无需赋权-->>"+saOppermission.getsActivityFName());
		            	//continue;
		            }
		            
		            
	            	//功能权限及菜单显示
            		//功能权限
	            	if(saOppermission.getsPermissionKind()==0){
	            		//0代表功能权限
		            	//取得systemFullID
	            		String url = saOppermission.getsProcess();
//	            		System.out.println(url);
	            		//角色realmRoles
	            		if(realmRoles.contains(url)==false){
			            	realmRoles.add(url);
	            		}
		            	
		            	//授权realmPermissions
		            	String actions  = saOppermission.getsActions();
		            	if(null!=actions && !"".equals(actions)){
		            		//处理权限
		            		String[] actionsArray = actions.split(",");
		            		for(int i=0;i<actionsArray.length;i++){
		            			String action = actionsArray[i];
		            			String permission = url + ":" + action;
		                		realmPermissions.add(permission);
		            		}
		            	}
	            		
		            	//导航菜单                       判断菜单是否显示
//		            	System.out.println("加载导航菜单，是否显示菜单："+sDisplay);
		            	if("Y".equals(sDisplay)){
		            		if(systemFullIDs.contains(systemFullID)==false){
				            	systemFullIDs.add(systemFullID);
		            		}else{
		            			System.out.println(systemFullID+"-->>加载导航菜单，功能权限存在，无需重复添加！");
		            		}
		            	}
	            		
	            		//加载数据权限只显示自己的数据
	            		if(dataAccessUrls.containsKey(url)==false){
	            			String dense = saOppermission.getsDataAccess();
	            			if(dense==null){
	            				dense = "Y";
	            			}
//			            	System.out.println("加载数据权限只显示自己的数据，在功能权限界面进行设置："+dense);
		            		dataAccessUrls.put(url, dense);  
	            		}else{
	            			System.out.println("加载数据权限只显示自己的数据,url存在，无需重复添加！");
	            		}
	            		
	            	}
	            	
	            	//数据权限//目前没有使用，感觉不太合适
//	            	System.out.println("加载数据权限");
	            	//数据权限
	            	if(saOppermission.getsPermissionKind()==1){
	            		//1代表数据权限
		            	//写入数据权限数组中
	            		if(dataAccessIDs.contains(systemFullID)==false){
			            	dataAccessIDs.add(systemFullID);
	            		}else{
	            			System.out.println("数据权限存在，无需重复添加！");
	            		}
	            	}
	            }
	        }
	        
	        
	        //菜单使用的systemFullID
//	        System.out.println("菜单使用的systemFullIDs列表如下：");
	        List<String> ids = new ArrayList<String>();
	        for (String systemFullID : systemFullIDs) {  
//	            System.out.println("systemFullID------------------->"+systemFullID);
	        	String[] idsArray = systemFullID.split("/"); 
	        	for(int i=0;i<idsArray.length;i++){
	        		String id = idsArray[i];
//	                System.out.println("id------------------->"+id);
	                if(!id.equals("")){
	            		//处理扩展名的问题
	            		String[] ss = id.split("\\.");
//	            		for(int j=0;j<ss.length;j++){
//	            			System.out.println("ss[j]------------------->"+ss[j]);
//	            		}
//	    	            System.out.println("fID------------------->"+ss[0]);
	            		//添加之前，判断是否已经存在
	            		boolean isExist = false;
	            		for(int x=0;x<ids.size();x++) {
	            			if(ids.get(x).equals(ss[0])) {
	            				isExist = true;
	            				break;
	            			}
	            		}
	            		if(isExist==false) {
		            		//不存在，添加
		            		ids.add(ss[0]);
	            		}
	                }
	        	}
	        } 
	        
	        //写入session（导航菜单）
//	        Session session = SecurityService.getCurrentSession();
//	        session.setAttribute("treeNavigation", ids);
	        SecurityService.setTreeNavigation(ids);
	        
//	        System.out.println("整理成导航菜单数组列表如下：");
//	        for (String id : ids) {
//	            System.out.println("------------------->"+id);
//	        }
	        
//	        dataAccessIDs.add("/systemID.ogn");
//	        session.setAttribute("dataAccessIDs", dataAccessIDs);
	        SecurityService.setDataAccessIDs(dataAccessIDs);

//	        System.out.println("数据访问权限数组列表如下：");
//	        for (String id : dataAccessIDs) {
//	            System.out.println("------------------->"+id);
//	        }
	        
//	        dataAccessUrls.put("key1", "value1");  
//	        dataAccessUrls.put("key2", "value2");  
//	        dataAccessUrls.put("key3", "value3");  
//	        dataAccessUrls.put("/customer/customerInfo/single", "protected");  
//	        session.setAttribute("dataAccessUrls", dataAccessUrls);
	        SecurityService.setDataAccessUrls(dataAccessUrls);
	        
//			System.out.println("开始打印数据密级配置清单......");
//			for(Map.Entry<String, String> entry : dataAccessUrls.entrySet()){
//				System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());  
//			}
		}

        //权限信息对象info,用来存放查出的用户的所有的角色（role）及权限（permission）  
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //用户的角色集合  
    	///////////////////////////////////////////////////////////////////////////
        info.setRoles(realmRoles);  
        ////////////////////////////////////////////////////////
        //用户的角色对应的所有权限，如果只使用角色定义访问权限，下面的四行可以不要  
        info.addStringPermissions(realmPermissions);
        ////////////////////////////////////////////////////////

//        System.out.println("SimpleAuthorizationInfo类中收集的角色列表如下：");
//        for(String r:info.getRoles()){
//        	System.out.println("------------------->"+r);
//        }
//        System.out.println("SimpleAuthorizationInfo类中收集的权限列表如下：");
//        for (String r : info.getStringPermissions()) {  
//            System.out.println("------------------->"+r);
//        } 

        return info;  

    }

	@Override
	public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
		// TODO Auto-generated method stub
		super.clearCachedAuthorizationInfo(principals);
	}
    
   
  
}  